using System.Globalization;

namespace StreamingClient.TSSplitter
{
    internal class MpegLayer3WaveFormat
    {
        /// <summary>
        /// Gets or sets the core WaveFormatExtensible strucutre representing the Mp3 audio data's
        /// core attributes. 
        /// </summary>
        /// <remarks>
        /// wfx.FormatTag must be WAVE_FORMAT_MPEGLAYER3 = 0x0055 = (85)
        /// wfx.Size must be >= 12
        /// </remarks>
        public WaveFormatExtensible WaveFormatExtensible { get; set; }

        /// <summary>
        /// Gets or sets the FormatTag that defines what type of waveform audio this is.
        /// </summary>
        /// <remarks>
        /// Set this to 
        /// MPEGLAYER3_ID_MPEG = 1
        /// </remarks>
        public short Id { get; set; }

        /// <summary>
        /// Gets or sets the bitrate padding mode. 
        /// This value is set in an Mp3 file to determine if padding is needed to adjust the average bitrate
        /// to meet the sampling rate.
        /// 0 = adjust as needed
        /// 1 = always pad
        /// 2 = never pad
        /// </summary>
        /// <remarks>
        /// This is different than the unmanaged version of MpegLayer3WaveFormat
        /// which has the field Flags instead of this name.
        /// </remarks>
        public int BitratePaddingMode { get; set; }

        /// <summary>
        /// Gets or sets the Block Size in bytes. For MP3 audio this is
        /// 144 * bitrate / samplingRate + padding
        /// </summary>
        public short BlockSize { get; set; }

        /// <summary>
        /// Gets or sets the number of frames per block.
        /// </summary>
        public short FramesPerBlock { get; set; }

        /// <summary>
        /// Gets or sets the encoder delay in samples.
        /// </summary>
        public short CodecDelay { get; set; }

        /// <summary>
        /// Returns a string representing the structure in little-endian 
        /// hexadecimal format.
        /// </summary>
        /// <remarks>
        /// The string generated here is intended to be passed as 
        /// CodecPrivateData for Silverlight 2's MediaStreamSource
        /// </remarks>
        /// <returns>
        /// A string representing the structure in little-endia hexadecimal
        /// format.
        /// </returns>
        public string ToHexString()
        {
            string s = WaveFormatExtensible.ToHexString();
            char[] mpeglayer3Data = new char[6 * 4];
            ToHexHelper(4, this.Id, 0, mpeglayer3Data);
            ToHexHelper(8, this.BitratePaddingMode, 4, mpeglayer3Data);
            ToHexHelper(4, this.BlockSize, 12, mpeglayer3Data);
            ToHexHelper(4, this.FramesPerBlock, 16, mpeglayer3Data);
            ToHexHelper(4, this.CodecDelay, 20, mpeglayer3Data);
            return s + new string(mpeglayer3Data);
        }
        /// <summary>
        /// Mask for the bits that make up the second hex digit in a byte.
        /// </summary>
        private const byte MaskTail = 0x0F;

        /// <summary>
        /// Mask for the bits that make up the first hex digit in a byte.
        /// </summary>
        private const byte MaskHead = 0xF0;
        public static void ToHexHelper(byte sizeOfField, long fieldData, int startIndex, char[] chars)
        {
            for (int i = 0; i < sizeOfField; i += 2, fieldData >>= 8, startIndex += 2)
            {
                chars[startIndex] = DecToHexConv[((fieldData & MaskHead) >> 4)];
                chars[startIndex + 1] = DecToHexConv[fieldData & MaskTail];
            }
        }

        private static readonly char[] DecToHexConv = new char[] 
                                                          {
                                                              '0',    /* 48 ascii */
                                                              '1',    /* 49 */
                                                              '2',    /* 50 */
                                                              '3',    /* 51 */
                                                              '4',    /* 52 */
                                                              '5',    /* 53 */
                                                              '6',    /* 54 */
                                                              '7',    /* 55 */
                                                              '8',    /* 56 */
                                                              '9',    /* 57 */
                                                              'A',    /* 65 ascii */
                                                              'B',    /* 66 */
                                                              'C',    /* 67 */
                                                              'D',    /* 68 */
                                                              'E',    /* 69 */
                                                              'F'     /* 70 */
                                                          };

        /// <summary>
        /// Returns a string representing all of the fields in the object.
        /// </summary>
        /// <returns>
        /// A string representing all of the fields in the object.
        /// </returns>
        public override string ToString()
        {
            return "MPEGLAYER3 "
                   + WaveFormatExtensible.ToString()
                   + string.Format(
                       CultureInfo.InvariantCulture,
                       "ID: {0}, Flags: {1}, BlockSize: {2}, FramesPerBlock {3}, CodecDelay {4}",
                       this.Id,
                       this.BitratePaddingMode,
                       this.BlockSize,
                       this.FramesPerBlock,
                       this.CodecDelay);
        }
    }
}